#include "StdAfx.h"
#include "PredictionArea.h"
#include "util.h"
#include "colors.h"

IDirect3DVertexDeclaration9* PredictionArea::areaDecl = NULL;

PredictionArea::PredictionArea(void) : m_fBase(0.25f), m_fHeight(16.0f), nVertices(3)
{
	createVtxDescription();
}


PredictionArea::~PredictionArea(void)
{
	// releae the com objects
	COM_RELEASE(this->areaDecl);
	COM_RELEASE(this->mp_VtxBuf);
	COM_RELEASE(this->mp_IndBuf);

	// free the memory
	FREE_MEMORY(vertices);
	FREE_MEMORY(indices);	
}

int PredictionArea::createVtxDescription(void)
{
	int rc = 0;
	if (this->areaDecl == NULL) // create the vertex decalation
	{
		struct DefaultVertex v;
		D3DVERTEXELEMENT9 decl[] = 
		{{0,0,D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
		 {0,0,D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
		 {0,0,D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
		D3DDECL_END()};
		decl[0].Offset = (char *) &v.pos - (char *) &v;
		decl[1].Offset = (char *) &v.normal - (char *) &v;
		decl[2].Offset = (char *) &v.color - (char *) &v;
		rc = md3dDev->CreateVertexDeclaration(decl, &areaDecl);
	}
	return 0;
}

float PredictionArea::ccw(const D3DXVECTOR3 p1, const D3DXVECTOR3 p2, const D3DXVECTOR3 p3) { return (p2.x - p1.x)*(p3.z - p1.z) - (p2.z - p1.z)*(p3.x - p1.x); }
bool PredictionArea::isLeftTurn(const D3DXVECTOR3 p1, const D3DXVECTOR3 p2, const D3DXVECTOR3 p3) { return ccw(p1, p2, p3) > 0; }
bool PredictionArea::isRightTurn(const D3DXVECTOR3 p1, const D3DXVECTOR3 p2, const D3DXVECTOR3 p3) { return ccw(p1, p2, p3) < 0; }
bool PredictionArea::isCollinear(const D3DXVECTOR3 p1, const D3DXVECTOR3 p2, const D3DXVECTOR3 p3) { return ccw(p1, p2, p3) == 0; }

void PredictionArea::set(const D3DXVECTOR3 playerPos, float playerAngle)
{
	// prediction area is a triangle
	C.x = playerPos.x;
	C.z = playerPos.z;

	L.x = C.x + m_fHeight*sin(playerAngle+m_fBase);
	L.z = C.z + m_fHeight*cos(playerAngle+m_fBase);

	R.x = C.x + m_fHeight*sin(playerAngle-m_fBase);
	R.z = C.z + m_fHeight*cos(playerAngle-m_fBase);

	// allocate memory
	vertices = (struct DefaultVertex *) malloc(sizeof(struct DefaultVertex) * nVertices);
	indices = (long *) malloc(sizeof(long) * 3);


	// fill the vertex buffer with positions
	for (int c = 0; c < nVertices; c++) vertices[c].color = BLUE;
	vertices[0].pos.x = C.x;
	vertices[0].pos.y = 2.0f;
	vertices[0].pos.z = C.z;

	vertices[1].pos.x = L.x;
	vertices[1].pos.y = 2.0f;
	vertices[1].pos.z = L.z;

	vertices[2].pos.x = R.x;
	vertices[2].pos.y = 2.0f;
	vertices[2].pos.z = R.z;

	// now their normals
	vertices[0].normal =  D3DXVECTOR3(0.0f, 1.0f, 0.0f);
	vertices[1].normal =  D3DXVECTOR3(0.0f, 1.0f, 0.0f);
	vertices[2].normal =  D3DXVECTOR3(0.0f, 1.0f, 0.0f);

	// now do the texture coordinates
	vertices[0].fU = 1.0f;
	vertices[0].fV = 1.0f;

	vertices[1].fU = 0.0f;
	vertices[1].fV = 0.0f;

	vertices[2].fU = 0.0f;
	vertices[2].fV = 0.0f;


	// fill the index buffer
	int k = 0;

	// front side quad
	indices[k++] = 0;
	indices[k++] = 1;
	indices[k++] = 2;
			

	// allocate memory in the graphics card memory for the vertices and the index buffer

	struct DefaultVertex *v = NULL;
	long *ind = NULL;

//#ifdef DEFAULT_SIMPLEMESH_SHADERS
//	rc =  md3dDev->CreateVertexBuffer(this->nVertices*sizeof(struct DefaultVertex), D3DUSAGE_WRITEONLY,
//		NULL, D3DPOOL_MANAGED, &this->mp_VtxBuf, NULL);
//#else 
//	rc =  md3dDev->CreateVertexBuffer(this->nVertices*sizeof(struct DefaultVertex), D3DUSAGE_WRITEONLY,
//		DEFAULT_VERTEX_FVF, D3DPOOL_MANAGED, &this->mp_VtxBuf, NULL);
//#endif

	md3dDev->CreateVertexBuffer(this->nVertices*sizeof(struct DefaultVertex), D3DUSAGE_WRITEONLY,
		DEFAULT_VERTEX_FVF, D3DPOOL_MANAGED, &this->mp_VtxBuf, NULL);

	// lock the buffer and copy the vertices (locking the entire array
	mp_VtxBuf->Lock(0, 0, (void **) &v, 0);

	memcpy(v, this->vertices, nVertices*sizeof(struct DefaultVertex));
	mp_VtxBuf->Unlock();
	md3dDev->CreateIndexBuffer(3*sizeof(long), D3DUSAGE_WRITEONLY, D3DFMT_INDEX32, 
		D3DPOOL_MANAGED, &this->mp_IndBuf, NULL);

	// lock the buffer and copy the vertices (locking the entire array
	mp_IndBuf->Lock(0, 0, (void **) &ind, 0);

	memcpy(ind, this->indices, 3*sizeof(long));
	mp_IndBuf->Unlock();

	// set up the material
	ZeroMemory(&material, sizeof(D3DMATERIAL9));
	material.Diffuse.r = RED.r;
	material.Diffuse.g = RED.g;
	material.Diffuse.b = RED.b;
	material.Diffuse.a = 0.5f;

	material.Specular.r = 150.0f;
	material.Specular.g = 150.0f;
	material.Specular.b = 150.0f;
	material.Power = 90.0f;

	D3DXCreateTextureFromFile(md3dDev,
							"data/texture_DR_preview.jpg",
							&texture);
	md3dDev->SetTexture(0,texture);
}

bool PredictionArea::contains(const D3DXVECTOR3 pos)
{
	int left = 0;
	int right = 0;
	int collinear = 0;

	// center to left
    if (isLeftTurn(C, L, pos)) left += 1;
	else if (isRightTurn(C, L, pos)) right += 1;
    else collinear += 1;

	// left to right
    if (isLeftTurn(L, R, pos)) left += 1;
	else if (isRightTurn(L, R, pos)) right += 1;
    else collinear += 1;

	// right to center
    if (isLeftTurn(R, C, pos)) left += 1;
	else if (isRightTurn(R, C, pos)) right += 1;
    else collinear += 1;

    if (left == 3 || right == 3) return true;
    if (left + collinear == 3) return true;
	if (right + collinear == 3) return true;
    return false;
}

void PredictionArea::Render(void)
{
	md3dDev->SetMaterial( &material );
	md3dDev->SetTexture(0, texture);
	md3dDev->SetStreamSource( 0, mp_VtxBuf, 0, sizeof(DefaultVertex) );
	md3dDev->SetIndices(mp_IndBuf); // set the index buffer
	md3dDev->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, this->nVertices, 0, 1);
}
